package com.neuronrobotics.replicator.gui.preview.android;

import java.util.ArrayList;
import java.util.Iterator;

import android.opengl.GLES20;

import com.neuronrobotics.opengl.scene.GLHandles;
import com.neuronrobotics.opengl.scene.ArrayShapeNode;
import com.neuronrobotics.replicator.gui.stl.STLFace;
import com.neuronrobotics.replicator.gui.stl.STLFacet;
import com.neuronrobotics.replicator.gui.stl.STLObject;
import com.neuronrobotics.replicator.gui.stl.STLWorkspaceObject;

public class STLShapeNodeFactory {
	
	public static ArrayShapeNode getSTLShape(STLObject stl,GLHandles theHandles){
		int numCoords = stl.getFacetAmount() * 3;
		float[] coordinates = new float[numCoords * 3];
		float[] normals = new float[numCoords * 3];
		
		int currCoord = 0;
		int currNorm = 0;
		
		Iterator<STLFace> theFaces = stl.getFaceIterator();
		while(theFaces.hasNext()){
			STLFace currFace = theFaces.next();
			for(STLFacet fac: currFace){
				fac.getVertices(coordinates, currCoord);
				currCoord += 9;
				
				currFace.getNormal(normals, currNorm);
				currNorm += 3;
				currFace.getNormal(normals, currNorm);
				currNorm += 3;
				currFace.getNormal(normals, currNorm);
				currNorm += 3;
			}
		}
		
		ArrayShapeNode result = new ArrayShapeNode(theHandles, coordinates, normals, GLES20.GL_TRIANGLES);
		result.setLightsOn(true);
			
		return result;
	}
	
	public static ArrayShapeNode getSTLFaceOutline(STLObject stl,GLHandles theHandles){
		
		int numCoords = stl.getFacetAmount() * 2 * 3;		
					
		float[] coordinates = new float[numCoords * 3];
		float[] normals = new float[numCoords * 3];
		
		int currCoord = 0;
		int currNorm = 0;
		
		Iterator<STLFacet> theFacets = stl.iterator();
		
		float[] temp = new float[9];
		
		while(theFacets.hasNext()){
			STLFacet currFacet = theFacets.next();
							
			currFacet.getVertices(temp, 0);
			
			loadOutlineLineData(temp,coordinates, currCoord);
			
			currCoord += 18;			
				
			currFacet.getNormal(normals, currNorm);
			currNorm += 3;
			currFacet.getNormal(normals, currNorm);
			currNorm += 3;
			currFacet.getNormal(normals, currNorm);
			currNorm += 3;
			currFacet.getNormal(normals, currNorm);
			currNorm += 3;
			currFacet.getNormal(normals, currNorm);
			currNorm += 3;
			currFacet.getNormal(normals, currNorm);
			currNorm += 3;
			
		}
		
		ArrayShapeNode result = new ArrayShapeNode(theHandles, coordinates, normals, GLES20.GL_LINES);
		result.setLightsOn(false);
			
		return result;
		
	}
	
	private static void loadOutlineLineData(float[] temp, float[] coordinates, int currCoord) {
		//a to b
				coordinates[currCoord] = temp[0];
				coordinates[currCoord+1] = temp[1];
				coordinates[currCoord+2] = temp[2];
				
				coordinates[currCoord+3] = temp[3];
				coordinates[currCoord+4] = temp[4];
				coordinates[currCoord+5] = temp[5];
				
				//a to c
				coordinates[currCoord+6] = temp[0];
				coordinates[currCoord+7] = temp[1];
				coordinates[currCoord+8] = temp[2];
				
				coordinates[currCoord+9] = temp[6];
				coordinates[currCoord+10] = temp[7];
				coordinates[currCoord+11] = temp[8];
				
				//b to c
				coordinates[currCoord+12] = temp[3];
				coordinates[currCoord+13] = temp[4];
				coordinates[currCoord+14] = temp[5];
				
				coordinates[currCoord+15] = temp[6];
				coordinates[currCoord+16] = temp[7];
				coordinates[currCoord+17] = temp[8];		
	}

	public static ArrayShapeNode getSTLFacetOutline(STLObject stl,GLHandles theHandles){
Iterator<STLFace> theFaces = stl.getFaceIterator();
		
		ArrayList<float[]> perims = new ArrayList<float[]>();
		ArrayList<float[]> norms = new ArrayList<float[]>();
		
		int numCoords = 0;	
		
		while(theFaces.hasNext()){
			STLFace currFace = theFaces.next();
			int currSize = currFace.getPerimterSize();
			float[] currPerim = new float[currSize*3];
			currFace.getPerimeter(currPerim);
			
			float[] currNormal = new float[3];
			currFace.getNormal(currNormal, 0);
			norms.add(currNormal);
			
			perims.add(currPerim);
			numCoords+=(currSize);
		}		
					
		float[] coordinates = new float[numCoords * 3];
		float[] normals = new float[numCoords * 3];
		
		int currCoord = 0;
		int currNorm = 0;
		int currNormInd = 0;
		for(float[] fArr:perims){
			float[] n = norms.get(currNormInd);
			for(float f:fArr){
				coordinates[currCoord]=f;
				if(currCoord%3==0) normals[currNorm++] = n[0];
				else if(currCoord%3==1) normals[currNorm++] = n[1];
				else normals[currNorm++] = n[2];
				currCoord++;
			}		
			
			currNormInd++;
			
		}
		
		ArrayShapeNode result = new ArrayShapeNode(theHandles, coordinates, normals, GLES20.GL_LINES);
		result.setLightsOn(false);
		
		return result;
	}
	
	public static ArrayShapeNode getSTLWorkspaceShape(STLWorkspaceObject stlw,GLHandles theHandles){
		STLFace theSurface = stlw.getSurfaceFace();

		int perimSize = theSurface.getPerimterSize();
		float[] perim = new float[perimSize*3];
		theSurface.getPerimeter(perim);
						
		float xMax = Float.NEGATIVE_INFINITY;
		float xMin = Float.POSITIVE_INFINITY;
		float zMax = Float.NEGATIVE_INFINITY;
		float zMin = Float.POSITIVE_INFINITY;
		for(int i=0;i<perimSize;i++){
			int curr = i*3;
			if(perim[curr]>xMax) xMax = perim[curr];
			if(perim[curr+2]>zMax) zMax = perim[curr+2];
			if(perim[curr]<xMin) xMin = perim[curr];
			if(perim[curr+2]<zMin) zMin = perim[curr+2];
			
		}
		
		//TODO this will only work for square surfaces
		float delta = 2.5f;
		
		float zLen = zMax - zMin;
		float xLen = xMax - xMin;
		
		//float xCent = (xMax+xMin)/2.0f;
		//float zCent = (zMax+zMin)/2.0f;
		
		int xSegments = (int)(xLen/delta)+1;
		int zSegments = (int)(zLen/delta)+1;
		
		float[] coords = new float[(xSegments*3 + zSegments*3)*2];
		for(int i=0;i<xSegments;i++){
			coords[i*6] = xMin+(i*delta);
			coords[i*6+1] = 0;//TODO
			coords[i*6+2] = zMin;
			coords[i*6+3] = xMin+(i*delta);
			coords[i*6+4] = 0;//TODO
			coords[i*6+5] = zMax;
		}
		for(int i=xSegments;i<xSegments+zSegments;i++){
			coords[i*6] = xMin;
			coords[i*6+1] = 0;//TODO
			coords[i*6+2] = zMin+(delta*(i-xSegments));
			
			coords[i*6+3] = xMax;
			coords[i*6+4] = 0;//TODO
			coords[i*6+5] = zMin+(delta*(i-xSegments));
		}
		
		float[] norms = new float[(xSegments*3 + zSegments*3)*2];
		
		
		
		ArrayShapeNode result = new ArrayShapeNode(theHandles, coords, norms, GLES20.GL_LINES);
		result.setColor(.15f, .15f, .15f, 1f);
		result.setLightsOn(false);
		
		return result;
	}
	
	
	
	
	public static ArrayShapeNode getSTLWorkspaceShapeOld(STLWorkspaceObject stlw,GLHandles theHandles){
		STLFace theSurface = stlw.getSurfaceFace();

		int numCoords = theSurface.getFacets().size() * 3;
		float[] coordinates = new float[numCoords * 3];
		float[] normals = new float[numCoords * 3];

		int currCoord = 0;
		int currNorm = 0;

		for (STLFacet fac : theSurface) {
			
			fac.getVertices(coordinates, currCoord);
			currCoord += 9;
			
			//theSurface.getNormal(normals, currNorm);
			normals[currNorm] = 0;
			normals[currNorm+1] = 1;
			normals[currNorm+2] = 0;
			currNorm += 3;
			//theSurface.getNormal(normals, currNorm);
			normals[currNorm] = 0;
			normals[currNorm+1] = 1;
			normals[currNorm+2] = 0;
			currNorm += 3;
			//theSurface.getNormal(normals, currNorm);
			normals[currNorm] = 0;
			normals[currNorm+1] = 1;
			normals[currNorm+2] = 0;
			currNorm += 3;
					
			
		}		
		ArrayShapeNode result = new ArrayShapeNode(theHandles, coordinates, normals, GLES20.GL_TRIANGLES);
		result.setColor(.15f, .15f, .15f, 1f);
		result.setLightsOn(false);
		
		return result;
	}
	
	

}
